package com.dlc.shop.seckill.common.listener;

import com.dlc.shop.bean.event.UpdateSeckillOrderSkuInfoEvent;
import com.dlc.shop.manager.impl.StockManager;
import lombok.AllArgsConstructor;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;


/**
 * @author yami
 */
@Component
@AllArgsConstructor
public class UpdateSeckillOrderSkuInfoListener {

    private final StockManager stockManager;

    @EventListener(UpdateSeckillOrderSkuInfoEvent.class)
    public void addInventory(UpdateSeckillOrderSkuInfoEvent event) {
        // TODO stock 退款还原库存数量
        // 库存是在redis中处理，订单退款状态是mysql中的数据，会有事务异常回滚的可能，所以要保证库存扣除的幂等和回滚
        // 处理步骤：1.还原sku库存，2.添加退款库存记录，3.将退款编号放到队列中，用于事务回滚后处理库存的回退操作 - 退款库存记录
        // 退款库存记录: 用于幂等判断，一个退款只能还原一次库存， key格式： cacheName:order_refund:退款id, value: 时间戳
        // 退款编号(退款id_时间戳): 避免退款中刚插入记录还没结束事务，定时任务就执行回退操作删除记录，时间间隔为两分钟(innodb_lock_wait_timeout默认时间是50s)

        // 事务回滚后操作：
        // 情况一：两分钟内再次发起退款，执行到还原库存时，判断到有退款还原库存记录，就不扣除库存，但替换退款库存记录value的时间戳为当前数据，且再插入退款编号到退款队列
        // 情况二：回滚后没有再次发起退款，订单状态还是未退款成功，定时任务两分钟后，将回退这里还原的库存，等待下次处理退款操作
        stockManager.orderRefundRollbackSecKillStock(event.getRefundId(), event.getSkuId(),
                event.getStockPointId(), event.getProdCount(), event.getRefundTime().getTime());
    }
}
